package org.embedchat.minatestcase;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.mina.common.IdleStatus;
import org.apache.mina.common.IoHandler;
import org.apache.mina.common.IoSession;
import org.junit.Assert;

public class TestIoHandler extends Assert implements IoHandler {

    private static Log log = LogFactory.getLog(TestIoHandler.class);

    private IoHandler testedHandler;

    private HashMap<Integer, IoSession> clientSessions = new HashMap<Integer, IoSession>();

    private HashMap<Integer, Set<Object>> messagesSendedToClietns = new HashMap<Integer, Set<Object>>();

    public TestIoHandler() {
    }

    public TestIoHandler(IoHandler handler) {
        this.testedHandler = handler;
    }

    public void closeTestSession(int clientUID) {
        IoSession session = clientSessions.get(clientUID);
        if (session != null) {
            try {
                sessionClosed(session);
                /**
                 * TODO check this. IDEA shows error here
                 */
                clientSessions.remove(session);
            } catch (Exception e) {
                log.error(e, e);
            }
        }
    }

    public void closeAllTestSessions() {
        for (Integer clientUID : clientSessions.keySet()) {
            closeTestSession(clientUID);
        }
    }

    /**
     * Emulation that this message received to server
     *
     * @param clientUID the client UID
     * @param message   the message
     */
    public void emulateMessageReceived(int clientUID, Object message) {
        IoSession session = clientSessions.get(clientUID);
        if (session == null) {
            session = new TestIoSession(this);
            clientSessions.put(clientUID, session);
        }
        try {
            messageReceived(session, message);
        } catch (Exception e) {
            log.error(e, e);
            fail(e.getMessage());
        }
    }

    /**
     * Validate that this message was sended
     *
     * @param clientUID the client UID
     * @param message   the message
     */
    public void assertMessageSend(int clientUID, Object message) {
        if (message == null) {
            return;
        }
        Set<Object> sendedMessages = messagesSendedToClietns.get(clientUID);
        if (sendedMessages == null) {
            fail("No one message was not sended to client " + clientUID);
        } else {
            for (Object sMessage : sendedMessages) {
                if (message.equals(sMessage)) {
                    return;
                }
            }
            log.debug("messages that sended: ");
            for (Object sMessage : sendedMessages) {
                log.debug(sMessage);
            }
            fail("Message (" + message + ") was not sended.");
        }
    }

    /**
     * Validate that no this class messages was sended
     * @param clientUID  the client UID
     * @param clazz the class of Message
     */
    public void assertMessageNotSended(int clientUID, Class clazz) {
        Set<Object> sendedMessages = messagesSendedToClietns.get(clientUID);
        if (sendedMessages == null) {
            return;
        }
        for (Object sMessage : sendedMessages) {
            if (clazz.equals(sMessage.getClass())) {
                fail("There are some wrong message that sended to client. Message class: " + clazz);
            }
        }
    }

    public void sessionCreated(IoSession session) throws Exception {
        testedHandler.sessionCreated(session);
    }

    public void sessionOpened(IoSession session) throws Exception {
        testedHandler.sessionOpened(session);
    }

    public void sessionClosed(IoSession session) throws Exception {
        testedHandler.sessionClosed(session);
    }

    public void sessionIdle(IoSession session, IdleStatus status) throws Exception {
        testedHandler.sessionIdle(session, status);
    }

    public void exceptionCaught(IoSession session, Throwable e) throws Exception {
        testedHandler.exceptionCaught(session, e);
    }

    public void messageReceived(IoSession session, Object message) throws Exception {
        log.debug("Message received: " + message);
        testedHandler.messageReceived(session, message);
    }

    public void messageSent(IoSession session, Object object) throws Exception {
        testedHandler.messageSent(session, object);
        for (Integer clientUID : clientSessions.keySet()) {
            if (clientSessions.get(clientUID).equals(session)) {
                Set<Object> sendedMessages = messagesSendedToClietns.get(clientUID);
                if (sendedMessages == null) {
                    sendedMessages = new HashSet<Object>();
                }
                sendedMessages.add(object);
                messagesSendedToClietns.put(clientUID, sendedMessages);
			}
		}
	}

}
